/*
    Author: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.cdiggins.com
*/

namespace cvm
{
	struct IArithmetic : BaseType
	{
		virtual void Eq(Any& x, Any& y) = 0;
		virtual void NEq(Any& x, Any& y) = 0;
		virtual void Lt(Any& x, Any& y) = 0;
		virtual void Gt(Any& x, Any& y) = 0;
		virtual void LtEq(Any& x, Any& y) = 0;
		virtual void GtEq(Any& x, Any& y) = 0;
		virtual void Add(Any& x, Any& y) = 0;
		virtual void Sub(Any& x, Any& y) = 0;
		virtual void Mul(Any& x, Any& y) = 0;
		virtual void Div(Any& x, Any& y) = 0;
		virtual void Mod(Any& x, Any& y) = 0;
		virtual void Neg(Any& x) = 0;
	};

	struct IFunction 
	{
		virtual void Apply(Any& fxn, VM& vm) = 0;
	};

	struct IList 
	{
		virtual void Map(Any& lst, Any& fxn) = 0;
		virtual void Fold(Any& lst, Any& init, Any& fxn) = 0;
		virtual void Count(Any& lst, Any& result) = 0;
		virtual void Empty(Any& lst, Any& result) = 0;
		virtual void Filter(Any& lst, Any& pred) = 0;
		virtual void ForEach(Any& lst, Any& fxn) = 0;
		virtual void GetAt(Any& list, Any& n) = 0;
		virtual void SetAt(Any& list, Any& n, Any& val) = 0;
		virtual void SwapAt(Any& list, Any& n, Any& m) = 0;
	};

	struct Int : ValType<IArithmetic>
	{	
		PChar TypeName() { return "Int"; } 
		void Write(Any& x, Any& y) { fprintf(y.ToFile(), "%d", x.ToInt()); } 
		void Eq(Any& x, Any& y) { x = x.ToInt() == y.ToInt(); }
		void NEq(Any& x, Any& y) { x = x.ToInt() != y.ToInt(); }
		void Lt(Any& x, Any& y) { x = x.ToInt() < y.ToInt(); }
		void Gt(Any& x, Any& y) { x = x.ToInt() > y.ToInt(); }
		void LtEq(Any& x, Any& y) { x = x.ToInt() <= y.ToInt(); }
		void GtEq(Any& x, Any& y) { x = x.ToInt() >= y.ToInt(); }
		void Add(Any& x, Any& y) { x = x.ToInt() + y.ToInt(); }
		void Sub(Any& x, Any& y) { x = x.ToInt() - y.ToInt(); }
		void Mul(Any& x, Any& y) { x = x.ToInt() * y.ToInt(); }
		void Div(Any& x, Any& y) { x = x.ToInt() / y.ToInt(); }
		void Mod(Any& x, Any& y) { x = x.ToInt() % y.ToInt(); }
		void Neg(Any& x) { x = -x.ToInt(); }
	};
	Int gInt;

	struct Dbl : ValType<IArithmetic>
	{	
		PChar TypeName() { return "Double"; } 
		void Write(Any& x, Any& y) { fprintf(y.ToFile(), "%f", x.ToDbl()); } 
		void Eq(Any& x, Any& y) { x = x.ToDbl() == y.ToDbl(); }
		void NEq(Any& x, Any& y) { x = x.ToDbl() != y.ToDbl(); }
		void Lt(Any& x, Any& y) { x = x.ToDbl() < y.ToDbl(); }
		void Gt(Any& x, Any& y) { x = x.ToDbl() > y.ToDbl(); }
		void LtEq(Any& x, Any& y) { x = x.ToDbl() <= y.ToDbl(); }
		void GtEq(Any& x, Any& y) { x = x.ToDbl() >= y.ToDbl(); }
		void Add(Any& x, Any& y) { x = x.ToDbl() + y.ToDbl(); }
		void Sub(Any& x, Any& y) { x = x.ToDbl() - y.ToDbl(); }
		void Mul(Any& x, Any& y) { x = x.ToDbl() * y.ToDbl(); }
		void Div(Any& x, Any& y) { x = x.ToDbl() / y.ToDbl(); }
		void Mod(Any& x, Any& y) { x = fmod(x.ToDbl(), y.ToDbl()); }
		void Neg(Any& x) { x = -x.ToDbl(); }
	};
	Dbl gDbl;

	struct Bool : ValType<BaseType>
	{	
		PChar TypeName() { return "Bool"; } 
		void Write(Any& x, Any& y) { if (x.ToBool()) fprintf(y.ToFile(), "true"); else fprintf(y.ToFile(), "false"); } 
		void And(Any& x, Any& y) { x = x.ToBool() && y.ToBool(); }
		void Or(Any& x, Any& y) { y = x.ToBool() || y.ToBool(); }
		void XOr(Any& x, Any& y) { y = x.ToBool() ^ y.ToBool(); }
		void Not(Any& x) { x = !x.ToBool(); }
	};
	Bool gBool;

	struct Char : ValType<BaseType>
	{	
		void Write(Any& x, Any& y) { fprintf(y.ToFile(), "%c", ToChar(x)); } 
		PChar TypeName() { return "Char"; } 
	};
	Char gChar;

	struct CString : ValType<BaseType>
	{
		void Write(Any& x, Any& y) { fprintf(y.ToFile(), "%s", ToPChar(x)); } 
		PChar TypeName() { return "CString"; } 
	};
	CString gCString;

	struct File : ValType<BaseType>
	{
		void Write(Any& x, Any& y) { fprintf(y.ToFile(), "file"); } 
		PChar TypeName() { return "File"; } 
	};
	File gFile;
}